import { getValue } from '$utils/get';
import { derived, get, writable, type Readable, type Writable } from 'svelte/store';
import EnLocaleConfig from './locales/en';
import ZhLocaleConfig from './locales/zh-cn';
import { getContext, setContext } from 'svelte';

type LanUnit = {
	[key: string]: boolean | string | number | LanUnit;
};

export type I18nLocale = LanUnit;

type FillValues = (string | number)[];

const __resolve_result = (value: string, argv: FillValues) => {
	if (argv.length === 0) return value;
	value = value.split('%%').reduce((prev, cur, i) => {
		prev += (argv[i] ? argv[i] : '') + cur;
		return prev;
	}, '');
	return value;
};

export type I18nExport = {
	origin: Writable<LanUnit>;
	locale: Writable<string>;
	t: Readable<(key: string, ...argv: FillValues) => string>;
	change: (fn?: ((lang: string) => void) | string) => void;
	set: (key: string, value: LanUnit) => void;
};

export const setupI18n = () => {
	const source = {
		[EnLocaleConfig.dateLocale]: EnLocaleConfig.message,
		[ZhLocaleConfig.dateLocale]: ZhLocaleConfig.message
	};
	const locale = writable<string>(EnLocaleConfig.dateLocale);
	const origin = writable<I18nLocale>(source[EnLocaleConfig.dateLocale]);

	locale.subscribe((value) => {
		origin.set(source[value]);
	});

	return {
		origin,
		locale,
		t: derived(origin, ($origin) => {
			return (key: string, ...argv: FillValues) => {
				if (!key) return '--i18key is empty--';
				if (typeof key !== 'string') return '--i18key is not string--';
				const result = getValue($origin, key, '--no value--') as string;
				return __resolve_result(result, argv);
			};
		}),
		change: (fn?: ((lang: string) => void) | string) => {
			if (typeof fn === 'string') return locale.set(fn);
			const toggleLan =
				get(locale) === EnLocaleConfig.dateLocale
					? ZhLocaleConfig.dateLocale
					: EnLocaleConfig.dateLocale;
			if (fn) fn(toggleLan);
			locale.set(toggleLan);
		},
		set: (key: string, value: LanUnit) => {
			origin.update((origin) => {
				let cur = origin;
				const keyList = key.split('.');
				const len = keyList.length;
				keyList.forEach((k, i) => {
					if (len - 1 === i) {
						cur[k] = value;
					} else cur = typeof cur[k] === 'object' ? cur[k] : (cur[k] = {});
				});

				return origin;
			});
		}
	};
};

export function initI18n() {
	const i18n = setupI18n();
	setContext('lan', i18n);
	return i18n;
}

export function useI18n() {
	return getContext<I18nExport>('lan');
}
